////////////////////////// 背景 /////////////////////////
// 需求: 创建一个 id 函数，传入什么数据就返回该数据本身（也就是说，参数和返回值类型相同）
// 实现思路1
function id(value: number): number {
    return value
}
// console.log(id(10));

// 实现思路2
function id1(value: any): any {
    return value
}
// console.log(id1(10));


////////////////////////// 泛类型 /////////////////////////
// 定义
function id2<abck>(value: abck): abck {
    return value
}

// // 调用(不加类型推断)
// console.log(id2<number>(19));
// console.log(id2<string>('string'));
// console.log(id2<boolean>(true));
// // 调用(加类型推断)
// console.log(id2(19))
// console.log(id2('string'))
// console.log(id2(true))

// 类型约束
// 1.指定更加具体的类型
function idNum<Type> (value: Type[]): Type[] {
    console.log(value.length);
    return value
}
// idNum([1,2,3])

////////////////////////// 泛型约束 /////////////////////////
// 2.泛型约束
// 2.1 单变量约束
// 接口约束
interface ILength {length: number}
// 使用约束
function idNumNew< TypeNew extends ILength > (value: TypeNew): TypeNew {
    console.log(value.length)
    return value
}
// idNumNew('111111')
// idNumNew([1,2,3])

// 2.2 多变量约束
function idNumNewNew<TypeNew, KeyNew extends keyof TypeNew>(obj: TypeNew, key: KeyNew): TypeNew[KeyNew] {
    return obj[key]
}
// console.log(idNumNewNew({name: 'black', age: 25}, 'name'));

////////////////////////// 泛型接口 /////////////////////////
// 3.泛型接口
// 定义
interface IDFunc<Type> {
    id: (value: Type) => Type
    ids: () => Type[]
}

// 使用
let obj204: IDFunc<number> = {
    id:(value) => { return value },
    ids() { return [1, 3, 5] }
}

// 数组也是个泛型接口
const nums = [1, 3, 5]
const strs = ['a', 'b', 'c']
strs.forEach(() => {})

// interface Array<T> {
//     length: number;
//     toString(): string;
//     toLocaleString(): string;
//     pop(): T | undefined;
//     push(...items: T[]): number;
//     concat(...items: ConcatArray<T>[]): T[];
//     concat(...items: (T | ConcatArray<T>)[]): T[];
//     join(separator?: string): string;
//     reverse(): T[];
//     shift(): T | undefined;
//     slice(start?: number, end?: number): T[];
//     sort(compareFn?: (a: T, b: T) => number): this;
//     splice(start: number, deleteCount?: number): T[];
//     splice(start: number, deleteCount: number, ...items: T[]): T[];
//     unshift(...items: T[]): number;
//     indexOf(searchElement: T, fromIndex?: number): number;
//     lastIndexOf(searchElement: T, fromIndex?: number): number;
//     every<S extends T>(predicate: (value: T, index: number, array: T[]) => value is S, thisArg?: any): this is S[];
//     every(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): boolean;
//     some(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): boolean;
//     forEach(callbackfn: (value: T, index: number, array: T[]) => void, thisArg?: any): void;
//     map<U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[];
//     filter<S extends T>(predicate: (value: T, index: number, array: T[]) => value is S, thisArg?: any): S[];
//     filter(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): T[];
//     reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T;
//     reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T;
//     reduce<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U;
//     reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T;
//     reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T;
//     reduceRight<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U;
//     [n: number]: T;
// }

let testArray204: Array<number> = [1,2,3]
// console.log(testArray204.push(2));

//////////////////////////// 泛类型类 /////////////////////////
// 定义
class GenericNumber<T> {
    // 属性
    defaultValue: T
    // 方法
    print = () => console.log(this.defaultValue)
    // 构造函数 
    constructor(defaultValue: T) {
        this.defaultValue = defaultValue
    }
} 
// 使用
const number204 = new GenericNumber<number>(18)
// console.log(number204.defaultValue);
// number204.print()

const string204 = new GenericNumber<string>('111')
// console.log(string204.defaultValue)
// string204.print()

const array204 = new GenericNumber<string[]>(['111'])
// console.log(array204.defaultValue)
// array204.print()

const object204 = new GenericNumber<{name: string}>({name: 'black'})
// console.log(object204.defaultValue)
// object204.print()

const number204New = new GenericNumber(18)
// console.log(number204New.defaultValue);
// number204New.print()


////////////////////////// 泛类型工具类 /////////////////////////
// TS 内置了一些常用的工具类型，来简化 TS 中的一些常见操作
// Partial<Type>
// 定义基准类
interface Props {
    id: string,
    age: number,
    children: number[]
}
// 创建新类，继承基准类，属性和方法可选择
type PartialProps = Partial<Props>

// 基准类的元素必须都声明
const myProp: Props = {
    id: 'black',
    age: 12,
    children: [1, 2, 3]
}
// 新类属性和方法都可选择
const myPartialProp: PartialProps = {

}

// Readonly<Type>
// 创建新类,继承基准类,属性只读
type readOnlyProps = Readonly<Props>

// 基准类的元素可改
myProp.id = 'white'
// 新类属性和方法不可改
const myReadOnlyProps: readOnlyProps = {
    id: 'black',
    age: 12,
    children: [1, 2, 3]
}
// myReadOnlyProps.children = [2]

// Pick<Keys,Type>
// 创建新类,继承基准类,类型选其中几个
type T = 'id' | 'age'
type pickProps = Pick<Props,T>

// 新类只有基准类id和age变量,没有children变量
const myPickProps: pickProps = {
    id: 'black',
    age: 12,
    // children: [1, 2, 3]
}

// Record<Keys,Type>
// 创建新类，键名为id和age，键值可定义
type recordProps = Record<T, number>
const myRecordProps: recordProps = {
    id: 1,
    age: 3
}